/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * \file
 * \brief Linux implementation of USB driver
 * \author Matthieu Myrsky <matthieu.myrsky@tkk.fi>
 * Implementation of the Linux USB driver.
 */
#include "USB_Linux.hpp"


//*****************************************************************************
CUSB_Linux::CUSB_Linux()
  : iOpen(false),
    iUsb_handle()
{

}
//*****************************************************************************

CUSB_Linux::~CUSB_Linux()
{
  Close();
}
//*****************************************************************************

bool CUSB_Linux::Open(struct usb_device *aDeviceToOpen)
{
  int i= 0;


  if(!iOpen){
    iUsb_handle = usb_open(aDeviceToOpen);
    if (iUsb_handle == NULL) {
      dPrint(1,"Not able to claim the USB device");
      return false;
    }
    //usb_detach_kernel_driver_np(iUsb_handle, 1);
    i = usb_set_configuration(iUsb_handle, 1);
    if (i < 0) {
      dPrint(1, 
             "Not able to set USB configuration 1"); 
      if(i == -16){
        dPrint(1,"device busy");
        
      }
      if (i == -12){
        dPrint(1,"no memory");
      }
      return false;
    }
    i = usb_claim_interface(iUsb_handle, 0);
    if(i < 0){
      dPrint(1,"Could not open interface number 1, error code %i\n", i);
      if(i == -16){
        dPrint(1,"device busy");
        
      }
      if (i == -12){
        dPrint(1,"no memory");
      }
      return false;
    }
    
    iOpen = true;
    return true;
  }else{
    dPrint(1,"Device already opened");
    return false;
  }

}
//*****************************************************************************

bool CUSB_Linux::Close(void)
{
  if(iOpen){
    int r = usb_close(iUsb_handle);
    if(r == 0){
      dPrint(3,"USB succesfully closed");
      return true;
    }else{
      dPrint(3,"Failed to close USB");
      return false;
    }
  }else{
    dPrint(3,"Device already closed");
    return false;
  }


}
//*****************************************************************************

int CUSB_Linux::Read(int endPoint,
                     char *aBuffer, 
                     unsigned int aSize, 
                     unsigned int aTimeout_ms)
{

  return usb_bulk_read(iUsb_handle,endPoint , aBuffer,aSize,aTimeout_ms);
  
}
//*****************************************************************************

int CUSB_Linux::Write(int endPoint,
                      char *aBuffer, 
                      unsigned int aSize, 
                      unsigned int aTimeout_ms)
{
  return usb_bulk_write(iUsb_handle,endPoint , aBuffer,aSize,aTimeout_ms);
}
//*****************************************************************************

int CUSB_Linux::ControlMessage(char *aBuffer, 
                               unsigned int aSize, 
                               unsigned int aTimeout_ms,
                               int aRequestType,
                               int aRequest,
                               int aRequestValue,
                               int aIndex){
 
  return usb_control_msg(iUsb_handle, aRequestType, aRequest, 
                         aRequestValue, aIndex, aBuffer, aSize, aTimeout_ms);

}
//*****************************************************************************

int CUSB_Linux::SearchForDevice(unsigned int aVendorId,
                                unsigned int aDeviceId,
                                struct usb_device *devs[])
{
  int numberOfDevs = 0;
  struct usb_bus *usb_bus;
  struct usb_device *dev;
  usb_init();
  usb_find_busses();
  usb_find_devices();
  for (usb_bus = usb_busses;
       usb_bus;
       usb_bus = usb_bus->next) {
    for (dev = usb_bus->devices;
         dev;
         dev = dev->next) {
      if ((dev->descriptor.idVendor
           == aVendorId) &&
          (dev->descriptor.idProduct
           == aDeviceId)){
        devs[numberOfDevs] = dev;
        numberOfDevs += 1;
      }
    }
  }
  return numberOfDevs;

}
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
